#include "Animation.h"

struct QuickTab
{
	double floats[6];

	void operator()(double a, double b, double c, double d, double e, double f)
	{
		floats[0] = a;
		floats[1] = b;
		floats[2] = c;
		floats[3] = d;
		floats[4] = e;
		floats[5] = f;
	}

	double& operator[](int i)
	{
		return floats[i];
	}
};

AnimationFrame::AnimationFrame(int aAnimation, int aFrame, int aSpeed)
{
	KeyFrame spine;
	KeyFrame neck;
	KeyFrame leftArm;
	KeyFrame rightArm;
	KeyFrame leftLeg;
	KeyFrame rightLeg;

	QuickTab angles;
	QuickTab lengths;
	int duration = aSpeed;

	angles(0,0,0,0,0,0);
	lengths(1,1,1,1,1,1);

	if(aAnimation == ANIMATION_NONE)
	{
		if(aFrame == 0)	angles(0,0,PI+PI/8,PI-PI/8,PI,PI);
	}

	if(aAnimation == ANIMATION_WALK_RIGHT)
	{
		if(aFrame == 0)	angles(PI/64,PI/16,PI-PI/8,PI+PI/8,PI+PI/12,PI-PI/8);
		if(aFrame == 1) angles(PI/96,PI/32,PI-PI/16,PI+PI/16,PI+PI/24,PI-PI/16);
		if(aFrame == 2) angles(0,0,PI,PI,PI,PI);
		if(aFrame == 3) angles(PI/96,PI/32,PI+PI/16,PI-PI/16,PI-PI/16,PI+PI/16);
		if(aFrame == 4) angles(PI/64,PI/16,PI+PI/8,PI-PI/8,PI-PI/8,PI+PI/8);
		if(aFrame == 5) angles(PI/96,PI/32,PI+PI/16,PI-PI/16,PI-PI/16,PI+PI/16);
		if(aFrame == 6) angles(0,0,PI,PI,PI,PI);
		if(aFrame == 7) angles(PI/96,PI/32,PI-PI/16,PI+PI/16,PI+PI/24,PI-PI/16);
	}

	if(aAnimation == ANIMATION_WALK_LEFT)
	{
		if(aFrame == 0)	angles(-PI/64,-PI/16,PI+PI/8,PI-PI/8,PI-PI/8,PI+PI/12);
		if(aFrame == 1) angles(-PI/96,-PI/32,PI+PI/16,PI-PI/16,PI-PI/16,PI+PI/24);
		if(aFrame == 2) angles(0,0,PI,PI,PI,PI);
		if(aFrame == 3) angles(-PI/96,-PI/32,PI-PI/16,PI+PI/16,PI+PI/16,PI-PI/16);
		if(aFrame == 4) angles(-PI/64,-PI/16,PI-PI/8,PI+PI/8,PI+PI/8,PI-PI/8);
		if(aFrame == 5) angles(-PI/96,-PI/32,PI-PI/16,PI+PI/16,PI+PI/16,PI-PI/16);
		if(aFrame == 6) angles(0,0,PI,PI,PI,PI);
		if(aFrame == 7) angles(-PI/96,-PI/32,PI+PI/16,PI-PI/16,PI-PI/16,PI+PI/24);
	}

	if(aAnimation == ANIMATION_WALK_UP)
	{
		duration*=2;

		if(aFrame == 0)	lengths(1,1,1,1,1,1);
		if(aFrame == 1) lengths(1,1,0.7,1,1.2,0.8);
		if(aFrame == 2) lengths(1,1,1,1,1,1);
		if(aFrame == 3) lengths(1,1,1,0.7,0.8,1.2);

		if(aFrame == 0)	angles(0,0,PI+PI/8,PI-PI/8,PI,PI);
		if(aFrame == 1)	angles(PI/32,0,PI+PI/8,PI-PI/8,PI,PI);
		if(aFrame == 2)	angles(0,0,PI+PI/8,PI-PI/8,PI,PI);
		if(aFrame == 3)	angles(-PI/32,0,PI+PI/8,PI-PI/8,PI,PI);
	}

	if(aAnimation == ANIMATION_WALK_DOWN)
	{
		duration*=2;

		if(aFrame == 0)	lengths(1,1,1,1,1,1);
		if(aFrame == 1) lengths(1,1,0.8,1.1,1.2,0.8);
		if(aFrame == 2) lengths(1,1,1,1,1,1);
		if(aFrame == 3) lengths(1,1,1.1,0.8,0.8,1.2);

		if(aFrame == 0)	angles(0,0,PI+PI/16,PI-PI/16,PI,PI);
		if(aFrame == 1)	angles(PI/32,0,PI+PI/16,PI-PI/16,PI,PI);
		if(aFrame == 2)	angles(0,0,PI+PI/16,PI-PI/16,PI,PI);
		if(aFrame == 3)	angles(-PI/32,0,PI+PI/16,PI-PI/16,PI,PI);
	}

	spine(angles[0],lengths[0],duration);
	neck(angles[1],lengths[1],duration);
	leftArm(angles[2],lengths[2],duration);
	rightArm(angles[3],lengths[3],duration);
	leftLeg(angles[4],lengths[4],duration);
	rightLeg(angles[5],lengths[5],duration);

	keyFrames.push_back(spine);
	keyFrames.push_back(neck);
	keyFrames.push_back(leftArm);
	keyFrames.push_back(rightArm);
	keyFrames.push_back(leftLeg);
	keyFrames.push_back(rightLeg);
}

KeyFrame* AnimationFrame::GetKeyFrame(int aI)
{
	return &(keyFrames[aI]);
}

Animation::Animation()
{
}

void Animation::Build(int aSpeed)
{
	speed = aSpeed;

	// Default pose
	AnimationFrame frame(ANIMATION_NONE,0,speed);
	defaultPose = frame;

	const int animationCount = 4;
	int animationFrames[animationCount] = {8,8,4,4};
	int actualAnim[animationCount] = {ANIMATION_WALK_RIGHT,ANIMATION_WALK_LEFT,ANIMATION_WALK_UP,ANIMATION_WALK_DOWN};
	vector<AnimationFrame>* actualFramesVector[animationCount] = {&walkRight, &walkLeft, &walkUp, &walkDown};

	for(int a=0; a<animationCount; a++)
	{
		// Load animations frames into vectors
		for(int i=0; i<animationFrames[a]; i++)
		{
			AnimationFrame frame(actualAnim[a],i,speed);
			(*actualFramesVector[a]).push_back(frame);
		}

		// Connect keyframes to form an animation
		for(int i=0; i<animationFrames[a]-1; i++)
		{
			for(int j=0; j<(*actualFramesVector[a])[i].GetKeyFramesCount(); j++)
				(*actualFramesVector[a])[i].GetKeyFrame(j)->nextFrame = (*actualFramesVector[a])[i+1].GetKeyFrame(j);
		}

		// Make an animation loop
		for(int j=0; j<(*actualFramesVector[a])[0].GetKeyFramesCount(); j++)
				(*actualFramesVector[a])[animationFrames[a]-1].GetKeyFrame(j)->nextFrame = (*actualFramesVector[a])[0].GetKeyFrame(j);
	}
}

AnimationFrame* Animation::GetFrame(int aAnimation)
{
	if(aAnimation == ANIMATION_NONE) return &defaultPose;
	if(aAnimation == ANIMATION_WALK_RIGHT) return &(walkRight[0]);
	if(aAnimation == ANIMATION_WALK_LEFT) return &(walkLeft[0]);
	if(aAnimation == ANIMATION_WALK_UP) return &(walkUp[0]);
	if(aAnimation == ANIMATION_WALK_DOWN) return &(walkDown[0]);

	return NULL;
}